package org.dromara.common.excel.convert

import cn.hutool.core.annotation.AnnotationUtil
import cn.hutool.core.convert.Convert
import cn.hutool.core.util.ObjectUtil
import cn.idev.excel.converters.Converter
import cn.idev.excel.enums.CellDataTypeEnum
import cn.idev.excel.metadata.GlobalConfiguration
import cn.idev.excel.metadata.data.ReadCellData
import cn.idev.excel.metadata.data.WriteCellData
import cn.idev.excel.metadata.property.ExcelContentProperty
import io.github.oshai.kotlinlogging.KotlinLogging
import org.dromara.common.core.utils.reflect.ReflectUtils.invokeGetter
import org.dromara.common.excel.annotation.ExcelEnumFormat
import java.lang.reflect.Field

/**
 * 枚举格式化转换处理
 *
 * @author Liang
 * @updater LikeYouDo
 * @date 2025/1/14 15:49
 */
open class ExcelEnumConvert : Converter<Any> {
    companion object {
        private val log = KotlinLogging.logger { }
    }

    override fun supportJavaTypeKey(): Class<Any> {
        return Any::class.java
    }

    override fun supportExcelTypeKey(): CellDataTypeEnum? {
        return null
    }

    override fun convertToJavaData(
        cellData: ReadCellData<*>,
        contentProperty: ExcelContentProperty,
        globalConfiguration: GlobalConfiguration?
    ): Any? {
        cellData.checkEmpty()
        // Excel中填入的是枚举中指定的描述
        val textValue: Any? = when (cellData.type) {
            CellDataTypeEnum.STRING, CellDataTypeEnum.DIRECT_STRING, CellDataTypeEnum.RICH_TEXT_STRING -> cellData.stringValue
            CellDataTypeEnum.NUMBER -> cellData.numberValue
            CellDataTypeEnum.BOOLEAN -> cellData.booleanValue
            else -> throw IllegalArgumentException("单元格类型异常!")
        }
        // 如果是空值
        if (textValue == null) {
            return null
        }
        val enumCodeToTextMap = beforeConvert(contentProperty)
        // 从Java输出至Excel是code转text
        // 因此从Excel转Java应该将text与code对调
        val enumTextToCodeMap: MutableMap<Any, Any> = HashMap()
        enumCodeToTextMap.forEach { (key, value) -> enumTextToCodeMap[value] = key }
        // 应该从text -> code中查找
        val codeValue = enumTextToCodeMap[textValue]
        return Convert.convert(contentProperty.field.type, codeValue)
    }

    override fun convertToExcelData(
        obj: Any?,
        contentProperty: ExcelContentProperty,
        globalConfiguration: GlobalConfiguration?
    ): WriteCellData<String> {
        if (obj == null) {
            return WriteCellData("")
        }
        val enumValueMap = beforeConvert(contentProperty)
        val value = Convert.toStr(enumValueMap[obj], "")
        return WriteCellData(value)
    }

    private fun beforeConvert(contentProperty: ExcelContentProperty): Map<Any, String> {
        val anno = getAnnotation(contentProperty.field)
        val enumValueMap: MutableMap<Any, String> = HashMap()
        val enumConstants: Array<out Enum<*>> = anno.enumClass.java.enumConstants
        for (enumConstant in enumConstants) {
            val codeValue = invokeGetter<Any>(enumConstant, anno.codeField)
            val textValue = invokeGetter<String>(enumConstant, anno.textField)
            enumValueMap[codeValue] = textValue
        }
        return enumValueMap
    }

    private fun getAnnotation(field: Field): ExcelEnumFormat {
        return AnnotationUtil.getAnnotation(field, ExcelEnumFormat::class.java)
    }
}
